package com.cp.support.gray;

import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.cp.support.HeaderConstant;
import com.google.common.base.Optional;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAvoidanceRule;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * ribbon负载均衡规则抽象, 提供选择server的能力
 * -针对gateway,普通的service,获取gray标识的方式不同
 * -留了一个扩展方法,如果后续还有必要的操作,则进行重写,默认为空
 *
 * @author YangXiaoLong
 * 2022/11/1 18:02
 */
public abstract class AbstractGrayRibbonRule extends ZoneAvoidanceRule {
    public static final String IS_GRAY = "true";


    /**
     * 获取灰度发布标识
     *
     * @return {@link boolean }
     * @author YangXiaoLong
     * 2022/11/2 10:59
     */
    public abstract boolean getGrayTag();


    @Override
    public Server choose(Object key) {
        try {
            boolean gray = getGrayTag();
            List<Server> servers = this.getLoadBalancer().getReachableServers();
            List<Server> grayServers = new ArrayList<>();
            List<Server> normalServers = new ArrayList<>();
            for (Server server : servers) {
                NacosServer nacosServer = (NacosServer) server;
                Map<String, String> metadata = nacosServer.getMetadata();
                if ((metadata.containsKey(HeaderConstant.GRAY_RELEASE))
                        && IS_GRAY.equals(metadata.get(HeaderConstant.GRAY_RELEASE))
                ) {
                    grayServers.add(server);
                } else {
                    normalServers.add(server);
                }
            }
            if (!gray) {
                return doChoose(normalServers, key);
            }
            return doChoose(grayServers, key);
        } finally {
            otherNecessaryOperation();
        }
    }

    /**
     * 不同的场景对tag的处理不一样, 作为扩展,如果需要操作
     *
     * @author YangXiaoLong
     * 2022/11/2 11:09
     */

    public void otherNecessaryOperation() {
    }

    @SuppressWarnings("all")
    private Server doChoose(List<Server> servers, Object key) {
        Optional<Server> server = super.getPredicate().chooseRandomlyAfterFiltering(servers, key);
        if (server.isPresent()) {
            return server.get();
        } else {
            return null;
        }
    }
}
